//////////////////////////////////////////////////
// EASIM project
// easim.omar.Stats
// 6/19/2007 8:29 PM
// Cong Liu
// gzcong@gmail.com

// Copyright (C) 2007
// All rights reserved.
// Refer to LICENSE of JIST (Java In Simulation Time) for terms and conditions of use.

package easim.omar;

import easim.net.Field;
import easim.win.SynControler;

import jist.swans.Constants;
import jist.runtime.JistAPI.DoNotRewrite;

public class Stats implements DoNotRewrite
{

  public String toString() {
    long time = easim.net.Clock.getTime();
    String second = "" + (time / Constants.SECOND);
    time %= Constants.SECOND;
    time /= Constants.MILLI_SECOND;
    String milli = "" + time;
    while (milli.length() < 3) milli = "0" + milli;
    return second + "." + milli + "\r\n" + getString();
  }

  public static Traffic average(Traffic[] traffic) {
    Traffic avg = new Traffic();
    for (int i = 0; i < traffic.length; ++ i) {
      avg.dtdvMsgs += traffic[i].dtdvMsgs;
      avg.ackMsgs += traffic[i].ackMsgs;
      avg.vectorMsgs += traffic[i].vectorMsgs;
      avg.dataMsgs1 += traffic[i].dataMsgs1;
      avg.dataMsgs2 += traffic[i].dataMsgs2;
      avg.omarMsgs += traffic[i].omarMsgs;
      avg.dtdvMsgSize += traffic[i].dtdvMsgSize;
      avg.ackMsgSize += traffic[i].ackMsgSize;
      avg.vectorMsgSize += traffic[i].vectorMsgSize;
      avg.dataMsgSize1 += traffic[i].dataMsgSize1;
      avg.dataMsgSize2 += traffic[i].dataMsgSize2;
      avg.omarMsgSize += traffic[i].omarMsgSize;
    }
    avg.dtdvMsgs /= traffic.length;
    avg.ackMsgs /= traffic.length;
    avg.vectorMsgs /= traffic.length;
    avg.dataMsgs1 /= traffic.length;
    avg.dataMsgs2 /= traffic.length;
    avg.omarMsgs /= traffic.length;
    avg.dtdvMsgSize /= traffic.length;
    avg.ackMsgSize /= traffic.length;
    avg.vectorMsgSize /= traffic.length;
    avg.dataMsgSize1 /= traffic.length;
    avg.dataMsgSize2 /= traffic.length;
    avg.omarMsgSize /= traffic.length;
    return avg;
  }

  public static class Traffic implements DoNotRewrite
  {
    public long dtdvMsgs = 0;
    public long ackMsgs = 0;
    public long vectorMsgs = 0;
    public long dataMsgs1 = 0;
    public long dataMsgs2 = 0;
    public long omarMsgs = 0;

    public long dtdvMsgSize = 0;
    public long ackMsgSize = 0;
    public long vectorMsgSize = 0;
    public long dataMsgSize1 = 0;
    public long dataMsgSize2 = 0;
    public long omarMsgSize = 0;

    public String toString() {
      return
        dtdvMsgs + " " +
        ackMsgs + " " +
        vectorMsgs + " " +
        dataMsgs1 + " " +
        dataMsgs2 + " " +
        omarMsgs + " " +
        dtdvMsgSize + " " +
        ackMsgSize + " " +
        vectorMsgSize + " " +
        dataMsgSize1 + " " +
        dataMsgSize2 + " " +
        omarMsgSize;
    }

    public void decrease(Traffic traffic) {
      dtdvMsgs -= traffic.dtdvMsgs;
      ackMsgs -= traffic.ackMsgs;
      vectorMsgs -= traffic.vectorMsgs;
      dataMsgs1 -= traffic.dataMsgs1;
      dataMsgs2 -= traffic.dataMsgs2;
      omarMsgs -= traffic.omarMsgs;
      dtdvMsgSize -= traffic.dtdvMsgSize;
      ackMsgSize -= traffic.ackMsgSize;
      vectorMsgSize -= traffic.vectorMsgSize;
      dataMsgSize1 -= traffic.dataMsgSize1;
      dataMsgSize2 -= traffic.dataMsgSize2;
      omarMsgSize -= traffic.omarMsgSize;
    }

    public void fromString(String line) {
      String[] data = line.split(" ");
      dtdvMsgs = Long.parseLong(data[0]);
      ackMsgs = Long.parseLong(data[1]);
      vectorMsgs = Long.parseLong(data[2]);
      dataMsgs1 = Long.parseLong(data[3]);
      dataMsgs2 = Long.parseLong(data[4]);
      omarMsgs = Long.parseLong(data[5]);
      dtdvMsgSize = Long.parseLong(data[6]);
      ackMsgSize = Long.parseLong(data[7]);
      vectorMsgSize = Long.parseLong(data[8]);
      dataMsgSize1 = Long.parseLong(data[9]);
      dataMsgSize2 = Long.parseLong(data[10]);
      omarMsgSize = Long.parseLong(data[11]);
    }

    public String getString() {
      return
        "dsdvMsgs = " + dtdvMsgs + "\r\n" +
        "ackMsgs = " + ackMsgs + "\r\n" +
        "vectorMsgs = " + vectorMsgs + "\r\n" +
        "dataMsgs1 = " + dataMsgs1 + "\r\n" +
        "dataMsgs2 = " + dataMsgs2 + "\r\n" +
        "omarMsgs = " + omarMsgs + "\r\n" +
        "dsdvMsgSize = " + dtdvMsgSize + "\r\n" +
        "ackMsgSize = " + ackMsgSize + "\r\n" +
        "vectorMsgSize = " + vectorMsgSize + "\r\n" +
        "dataMsgSize1 = " + dataMsgSize1 + "\r\n" +
        "dataMsgSize2 = " + dataMsgSize2 + "\r\n" +
        "omarMsgSize = " + omarMsgSize;
    }
  }
  
  public static Values average(Values[] values) {
    Values avg = new Values();
    for (int i = 0; i < values.length; ++ i) {
      avg.data += values[i].data;
      avg.acks += values[i].acks;
      avg.delay += values[i].delay;
      avg.buf += values[i].buf;
      avg.ackSize += values[i].ackSize;
      avg.vectorSize += values[i].vectorSize;
      avg.dtdvUtility += values[i].dtdvUtility;
      avg.swUtility += values[i].swUtility;
      avg.newDtdvAllocationPoint += values[i].newDtdvAllocationPoint;
      avg.currentDtdvAllocationPoint += values[i].currentDtdvAllocationPoint;
    }
    avg.data /= values.length;
    avg.acks /= values.length;
    avg.delay /= values.length;
    avg.buf /= values.length;
    avg.ackSize /= values.length;
    avg.vectorSize /= values.length;
    avg.dtdvUtility /= values.length;
    avg.swUtility /= values.length;
    avg.newDtdvAllocationPoint /= values.length;
    avg.currentDtdvAllocationPoint /= values.length;
    return avg;
  }

  public static class Values implements DoNotRewrite
  {
    public long data;
    public long acks;
    public long delay;
    public int buf;
    public int ackSize;
    public int vectorSize;
    public double dtdvUtility;
    public double swUtility;
    public double newDtdvAllocationPoint;
    public double currentDtdvAllocationPoint;
    public double dtdvMaxHop;

    public void decrease(Values values) {
      data -= values.data;
      acks -= values.acks;
    }

    public String toString() {
      return
        data + " " + // 14
        acks + " " + 
        delay + " " + 
        buf + " " + 
        ackSize + " " + 
        vectorSize + " " + 
        dtdvUtility + " " + 
        swUtility + " " + 
        newDtdvAllocationPoint + " " + 
        currentDtdvAllocationPoint + " " + 
        dtdvMaxHop;
    }

    public void fromString(String line) {
      String[] data1 = line.split(" ");
      data = Long.parseLong(data1[0]);
      acks = Long.parseLong(data1[1]);
      delay = Long.parseLong(data1[2]);
      buf = Integer.parseInt(data1[3]);
      ackSize = Integer.parseInt(data1[4]);
      vectorSize = Integer.parseInt(data1[5]);
      dtdvUtility = Double.parseDouble(data1[6]);
      swUtility = Double.parseDouble(data1[7]);
      newDtdvAllocationPoint = Double.parseDouble(data1[8]);
      currentDtdvAllocationPoint = Double.parseDouble(data1[9]);
      dtdvMaxHop = Double.parseDouble(data1[10]);
    }
  }

  public static Traffic send = new Traffic();
  public static Traffic recv = new Traffic();
  public static Values values = new Values();

  public static long data = 0;
  public static long acks = 0;
  public static long delay = 0;

  public static String getString() {
    int[] sizes = getSizes();
    double[] data2 = getData();
    return
      "-- send --\r\n" +
      send.getString() + "\r\n" +
      "-- recv --\r\n" +
      recv.getString() + "\r\n" +
      "-- stats --\r\n" +
      "data = " + data + "\r\n" +
      "acks = " + acks + "\r\n" +
      "delay = " + delay + "\r\n" +
      "buffer-size = " + sizes[0] + "\r\n" +
      "acks-size = " + sizes[1] + "\r\n" +
      "vectors-size = " + sizes[2] + "\r\n" +
      "dtdvUtility = " + data2[0] + "\r\n" +
      "swUtility = " + data2[1] + "\r\n" +
      "newDtdvAllocationPoint = " + data2[2] + "\r\n" +
      "currentDtdvAllocationPoint = " + data2[3] + "\r\n" +
      "currentDtdvAllocationPoint2 = " + data2[4] + "\r\n" +
      "dtdvMaxHop = " + data2[5];
  }

  public static String getString2() {
    int[] sizes = getSizes2();
    double[] data2 = getData2();
    return
      send + "\r\n" +
      recv + "\r\n" +
      data + " " + acks + " " + delay + " " + 
      sizes[0] + " " + sizes[1] + " " + sizes[2] + " " + 
      data2[0] + " " + data2[1] + " " + data2[2] + " " + data2[3] + " " + data2[4] + " " + data2[5];
  }

  public static void print() {
    System.out.println(getString());
  }

  public static void clear() {
    send = new Traffic();
    recv = new Traffic();
    data = 0;
    acks = 0;
    delay = 0;
  }

  protected static class Interactor1 implements SynControler.Interactor, DoNotRewrite
  {
    public easim.net.Node[] nodes;
    public int bufsize = 0;
    public int acks = 0;
    public int vectors = 0;
    public void interactorAction() {
      for (int i = 0; i < nodes.length; ++ i) {
        Node node = (Node)nodes[i];
        bufsize += node.data.cleanBuffer();
        acks += node.ack.acks.size();
        vectors += node.vector.cleanVector();
      }
    }
  }

  public static int[] getSizes() {
    Interactor1 interactor = new Interactor1();
    interactor.nodes = SynControler.getAllNodes();
    SynControler.interact(interactor);
    int[] sizes = new int[3];
    if (interactor.nodes.length == 0) return sizes;
    sizes[0] = (interactor.bufsize / interactor.nodes.length);
    sizes[1] = (interactor.acks / interactor.nodes.length);
    sizes[2] = (interactor.vectors / interactor.nodes.length);
    return sizes;
  }

  public static int[] getSizes2() {
    easim.net.Node[] nodes = Field.getAllNodes();
    int bufsize = 0;
    int acks = 0;
    int vectors = 0;
    for (int i = 0; i < nodes.length; ++ i) {
      Node node = (Node)nodes[i];
      bufsize += node.data.cleanBuffer();
      acks += node.ack.acks.size();
      vectors += node.vector.cleanVector();
    }
    int[] sizes = new int[3];
    if (nodes.length == 0) return sizes;
    sizes[0] = (bufsize / nodes.length);
    sizes[1] = (acks / nodes.length);
    sizes[2] = (vectors / nodes.length);
    return sizes;
  }

  protected static class Interactor2 implements SynControler.Interactor, DoNotRewrite
  {
    public easim.net.Node[] nodes;
    public double dtdvMaxHop = 0;
    public double dtdvUtility = 0;
    public double swUtility = 0;
    public double newDtdvAllocationPoint = 0;
    public double currentDtdvAllocationPoint = 0;
    public double currentDtdvAllocationPoint2 = 0;
    public void interactorAction() {
      for (int i = 0; i < nodes.length; ++ i) {
        Node node = (Node)nodes[i];
        dtdvMaxHop += node.dtdv.maxHop;
        dtdvUtility += node.timeStats.dtdvUtility();
        swUtility += node.timeStats.swUtility();
        newDtdvAllocationPoint += node.timeStats.newDtdvAllocationPoint();
        currentDtdvAllocationPoint += node.timeStats.currentDtdvAllocationPoint();
        currentDtdvAllocationPoint2 += node.timeStats.currentDtdvAllocationPoint2();
      }
      dtdvMaxHop /= nodes.length;
      dtdvUtility /= nodes.length;
      swUtility /= nodes.length;
      newDtdvAllocationPoint /= nodes.length;
      currentDtdvAllocationPoint /= nodes.length;
      currentDtdvAllocationPoint2 /= nodes.length;
    }
  }

  public static double[] getData() {
    Interactor2 interactor = new Interactor2();
    interactor.nodes = SynControler.getAllNodes();
    SynControler.interact(interactor);
    double[] data = new double[6];
    if (interactor.nodes.length == 0) return data;
    data[0] = interactor.dtdvUtility;
    data[1] = interactor.swUtility;
    data[2] = interactor.newDtdvAllocationPoint;
    data[3] = interactor.currentDtdvAllocationPoint;
    data[4] = interactor.currentDtdvAllocationPoint2;
    data[5] = interactor.dtdvMaxHop;
    return data;
  }

  public static double[] getData2() {
    easim.net.Node[] nodes = Field.getAllNodes();
    double dtdvUtility = 0;
    double swUtility = 0;
    double newDtdvAllocationPoint = 0;
    double currentDtdvAllocationPoint = 0;
    double currentDtdvAllocationPoint2 = 0;
    double dtdvMaxHop = 0;
    for (int i = 0; i < nodes.length; ++ i) {
      Node node = (Node)nodes[i];
      dtdvUtility += node.timeStats.dtdvUtility();
      swUtility += node.timeStats.swUtility();
      newDtdvAllocationPoint += node.timeStats.newDtdvAllocationPoint();
      currentDtdvAllocationPoint += node.timeStats.currentDtdvAllocationPoint();
      currentDtdvAllocationPoint2 += node.timeStats.currentDtdvAllocationPoint2();
      dtdvMaxHop += node.dtdv.maxHop;
    }
    dtdvUtility /= nodes.length;
    swUtility /= nodes.length;
    newDtdvAllocationPoint /= nodes.length;
    currentDtdvAllocationPoint /= nodes.length;
    currentDtdvAllocationPoint2 /= nodes.length;
    dtdvMaxHop /= nodes.length;
    double[] data = new double[6];
    if (nodes.length == 0) return data;
    data[0] = dtdvUtility;
    data[1] = swUtility;
    data[2] = newDtdvAllocationPoint;
    data[3] = currentDtdvAllocationPoint;
    data[4] = currentDtdvAllocationPoint2;
    data[5] = dtdvMaxHop;
    return data;
  }

  public Traffic send1;
  public Traffic recv1;
  public Values values1;

  public void fromString(String[] lines) {
    send1 = new Traffic();
    send1.fromString(lines[0]);
    recv1 = new Traffic();
    recv1.fromString(lines[1]);
    values1 = new Values();
    values1.fromString(lines[2]);
  }

}
